namespace Brjnk.GpxExplorer.Workspace
{
    using System;
    using System.ComponentModel;
    using Brjnk.GpxExplorer.Workspace.ApplicationStates;
    using Brjnk.GpxExplorer.Workspace.Searching;

    /// <summary>
    /// </summary>
    public class ApplicationStateManager : INotifyPropertyChanged
    {
        private bool isMapMode;
        private DataView view;
        private DataChangeWatcher watcher;
        private SearchService searchService;

        public ApplicationStateManager(DataView view, DataChangeWatcher watcher, SearchService searchService)
        {
            this.view = view;
            this.watcher = watcher;
            this.searchService = searchService;

            view.PropertyChanged += new PropertyChangedEventHandler(view_PropertyChanged);
            isMapMode = view.MapMode;
            watcher.ObjectRemoved += new EventHandler<WatcherEventArgs<object>>(watcher_ObjectRemoved);
            searchService.SearchedItems.ItemsRemovedUntyped += new EventHandler<MVVM.ItemsEventArgs>(SearchedItems_ItemsRemovedUntyped);
        }

        private void SearchedItems_ItemsRemovedUntyped(object sender, MVVM.ItemsEventArgs e)
        {
            foreach (var obj in e.Items)
                AbortIfObjectRemoved(obj);
        }

        private void watcher_ObjectRemoved(object sender, WatcherEventArgs<object> e)
        {
            AbortIfObjectRemoved(e.Object);
        }

        private void AbortIfObjectRemoved(object obj)
        {
            if (Current == null || Current.AbortAfterObjectRemoved == null) return;
            foreach (var i in Current.AbortAfterObjectRemoved)
            {
                if (object.ReferenceEquals(i, obj))
                { Abort(); break; }
            }
        }

        private void view_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "MapMode")
            {
                isMapMode = view.MapMode;
                if ((object)Current != null && !IsAvailable(Current))
                    Abort();
            }
        }

        public void Abort()
        {
            if ((object)Current != null)
            {
                Current.End -= new EventHandler(Current_End);
                Current.Abort();
                Current = null;
            }
        }

        public void SetState(ApplicationState state)
        {
            if (IsAvailable(state))
            {
                if ((object)current != null)
                    Abort();
                Current = state;
                Current.End += new EventHandler(Current_End);
            }
        }

        private void Current_End(object sender, EventArgs e)
        {
            Current.End -= new EventHandler(Current_End);
            Current = null;
        }

        private bool IsAvailable(ApplicationState state)
        {
            return (isMapMode && state.AvailableInMapMode) || (!isMapMode && state.AvailableInGraphMode);
        }

        private ApplicationState current;

        public ApplicationState Current
        {
            get { return current; }
            private set { current = value; OnPropertyChanged("Current"); }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}